home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / forc_c.zip / C.TXT
Text File  |  1995-01-26  |  32KB  |  779 lines

  1.  
  2.                 Linking C functions with your Force programs
  3.               ------------------------------------------------
  4.  
  5.   Overview
  6.   --------
  7.  
  8.   When writing complex programs or applications, you may find that you
  9.   need features that Force does not provide in the Force library, yet do
  10.   not want to give up the benefits that Force provides for execution
  11.   time and size.  This is where third party libraries may come to your
  12.   rescue.  Third party libraries are code libraries of functions and
  13.   procedures written by a company other than SEC, usually for Force
  14.   applications.  However, because of Force's flexibility, you may use
  15.   thousands of third party libraries that were written for Microsoft or
  16.   Borland C compilers.  Third party libraries often cover whole suites
  17.   of topics, or limit themselves to offering all possible features of
  18.   one specific topic.  Common third party libraries provide support for
  19.   computer graphics, accounting, higher-level mathematics, and other
  20.   topics.
  21.  
  22.   The third party libraries written specifically for Force usually ship
  23.   with their own Force header files for the functions and procedures in
  24.   their library, but third party libraries written for C compilers or
  25.   assemblers do not.
  26.  
  27.   You may also already have functions that you have written in C or
  28.   assembler, but want to use in your Force programs.  For whatever
  29.   reason that you decide to use a third party or C function library with
  30.   your application, use this section as a guideline for making the
  31.   library work with you, not against you.
  32.  
  33.  
  34.   Who's Compatible, and Who's not
  35.  
  36.   At the time of this writing, only two major C compilers are
  37.   compatible with the Force compiler.  Those are Microsoft C versions
  38.   5.0 and 6.0, and Borland's Turbo C versions 2.0 through 4.02.
  39.   Microsoft's current C/C++ compiler (version 7.0) generates compatible
  40.   code, but Force is not compatible with its runtime library.  Other,
  41.   less well-known C compilers may or may not be compatible with Force
  42.   depending on whether or not they generate standard Intel object code
  43.   .OBJ files.
  44.  
  45.   Understanding the basis of the lack of compatibility makes a number
  46.   of other facts readily sensible.
  47.  
  48.   Microsoft incompatibility is not marked, and in many cases MS C is
  49.   actually compatible in later versions.  FORCE is completely compatible
  50.   with Microsoft C versions up through 6.x (remember that you have to
  51.   link in the appropriate MICROx.OBJ file if MS runtime library
  52.   functions are called).  In MS C version 7.x, it appears that the
  53.   actual compiler code and much of the runtime library code is
  54.   compatible.  Incompatibilities center around the use of DBL numbers
  55.   (floats) in MS code as Microsoft's handling of these numbers departed
  56.   from strict IEEE conventions as of MS version 7.0; consequently, MS C
  57.   versions 7.x and 8.x (VC) produce C code that should be compatible
  58.   with FORCE as long as floats are not used in the C code or in the MS
  59.   runtime library functions called.  This problem is currently under
  60.   examination. There are thus indications that MS C versions 7.x and 8.x
  61.   are in fact compatible if the "alternate math" compiler switch and
  62.   MS C libraries are used, but this has not been tested completely at
  63.   the time of this writing.
  64.  
  65.   In any event, it appears from experiment that MS Quick C version 2.x
  66.   is also compatible with FORCE, and other C compilers may be as well.
  67.   Please notify SEC via email at Compuserve address 76660,1024 if you
  68.   have found other C compilers that are compatible so that we may share
  69.   this information with other FORCE users.
  70.  
  71.   In no event is C++ code compatible with FORCE!
  72.  
  73.   As for assemblers, both Borland's Turbo Assembler (all versions) and
  74.   Microsoft's Macro Assembler (all versions) generate .OBJ files that
  75.   are compatible with Force.
  76.  
  77.   Before we get started, let us just be sure where we stand.  Assumed
  78.   knowledge for the next subsection, Interfacing With C, is that you are
  79.   learned and comfortable with the C language.  We will not attempt to
  80.   teach any aspects of the language to you, other than for purposes of
  81.   review.
  82.  
  83.   Interfacing with C
  84.  
  85.        ╒════════════════════════════════════════════════╕
  86.        │  Force Data Type         C Data Type     bytes │
  87.        │  --------------------------------------------- │
  88.        │  BYTE                    signed char     1     │
  89.        │  (U)INT(unsigned)        int             2     │
  90.        │  (U)LONG(unsigned)       long            4     │
  91.        │  DBL                     double          8     │
  92.        │  LOGICAL                 int             2     │
  93.        │  CHAR                    char                  │
  94.        │  []                      variable              │
  95.        │  --------------------------------------------- │
  96.        │        Table 8-1 - Force/C data types          │
  97.        ╘════════════════════════════════════════════════╛
  98.  
  99.   C and Force share a very similar language and implementation
  100.   structure, a trait that allows the two to work together beautifully.
  101.   Force and C use the stack in the same way, use data segments in the
  102.   same way and implement functions and procedures nearly identically.
  103.   C's primitive data types match Force's very well (see Table 8-1).
  104.   Note the variable length in bytes of the data type CHAR.  CHAR's C
  105.   equivalent is an array of characters, which is determined at compile
  106.   time.
  107.  
  108.   The higher-level Force data types, such as a FILE, ALIAS and MEMO
  109.   have no real C equivalents, since they are in a real sense not actual
  110.   data types but rather "predefined data structures".
  111.  
  112.  
  113.   Passing Parameters to C Functions
  114.  
  115.   C has various methods of passing parameters, just as Force does
  116.   (please reference MEMORY MANAGEMENT, Passing Parameters, for a
  117.   full discussion on how Force passes parameters).  C has a CONST
  118.   keyword to signify that no modifications to the parameter are
  119.   allowed in the function.  C also allows passing by value, but does
  120.   not use a VALUE keyword; it is implied.  Finally, C allows passing
  121.   by reference, which is implemented by passing the address or
  122.   pointer as the parameter.
  123.  
  124.   ╒═════════════════════════════════════════════════════════════════════════╕
  125.   │  Parameter passing     Will Pass         use in Force     use in C      │
  126.   │  -----------------------------------------------------------------      │
  127.   │  by value                a copy          VALUE keyword    implied       │
  128.   │                                                                         │
  129.   │  by reference            the address     implied          address       │
  130.   │                                                           or pointer    │
  131.   │  constant value          a copy,         none             const keyword │
  132.   │                          but will not                                   │
  133.   │                          modify                                         │
  134.   │                                                                         │
  135.   │  constant reference      the address,   CONST  keyword    const keyword │
  136.   │                          but will not                     plus address  │
  137.   │                          modify                           or pointer    │
  138.   │                                                                         │
  139.   │  ------------------------------------------------------------------     │
  140.   │           Table 8-2 - Passing parameters in Force and C                 │
  141.   ╘═════════════════════════════════════════════════════════════════════════╛
  142.  
  143.   Table 8-2 shows how Force and C implement the different parameter
  144.   passing methods.  When passing by value, Force uses the VALUE keyword,
  145.   otherwise, passing by reference is implied in Force.  The opposite is
  146.   true with C: C passes parameters by value, unless the address of the
  147.   parameter is passed.  The one exception to this rule is for arrays.  C
  148.   always passes the address of an array, where Force will allow you to
  149.   pass a copy of the array.  Because Force CHAR types correspond to a
  150.   character array in C, you must pass CHAR parameters by reference.  Of
  151.   course, the same applies to other types of arrays.
  152.  
  153.   Let's take a look at some Force function prototypes, and try to write
  154.   corresponding C function prototypes.  First, we'll try passing by
  155.   value.
  156.  
  157.     FUNCTION UINT fn PROTOTYPE
  158.        PARAMETERS VALUE UINT x, VALUE DBL y
  159.  
  160.   This function, if written in Force, returns an unsigned integer value,
  161.   and takes two parameters, an integer x and a double precision value y.
  162.   Because the parameters are values, the corresponding function
  163.   prototype in C would be:
  164.  
  165.     unsigned int fn( int x, double y );
  166.  
  167.   Seems simple enough.  Now, let's try passing by reference.  This
  168.   procedure will take a CHAR string and a long integer as its
  169.   parameters:
  170.  
  171.     PROCEDURE proc PROTOTYPE
  172.        PARAMETERS CHAR string, ULONG x
  173.  
  174.   Recall from MEMORY MANAGEMENT that passing by reference means passing
  175.   the address of (or passing a pointer to) the parameter.  Thus, a
  176.   corresponding C function prototype would be expecting pointers to the
  177.   parameters:
  178.  
  179.     void proc( char * string, long * x );
  180.  
  181.   If we were to modify the procedure so that the parameters were to be
  182.   constant (non-modifiable by the procedure), we would add the CONST
  183.   keyword to our parameters:
  184.  
  185.     PROCEDURE proc PROTOTYPE
  186.        PARAMETERS CONST CHAR string, CONST ULONG x
  187.  
  188.   The corresponding C function would have the same changes:
  189.  
  190.     void proc( const char * string, const long * x );
  191.  
  192.   Now let's have a look at arrays.  Remember that C always expects the
  193.   address of the (first element of the) array, therefore, you cannot
  194.   pass a copy of the array to C. This function takes an array of
  195.   integers and the number of integers in the array as its parameters.
  196.   It returns some integer value.
  197.  
  198.     FUNCTION UINT fn PROTOTYPE
  199.        PARAMETERS UINT array[12], VALUE UINT length
  200.  
  201.   The corresponding C function prototype looks like this:
  202.  
  203.     int fn( int array[12], int length );
  204.  
  205.   Finally, let's take a look at one Force/C discrepancy, a function that
  206.   returns a CHAR data type.  The Force library function upper() takes a
  207.   CHAR parameter and returns its uppercase equivalent.  The Force
  208.   function prototype for upper() is as follows (note the CONST because
  209.   the original string is not modified).
  210.  
  211.     FUNCTION CHAR upper PROTOTYPE
  212.        PARAMETERS CONST CHAR source_string
  213.  
  214.   You would expect the corresponding C prototype to return...  Well,
  215.   what would it return?  A CHAR in C and Force is an array of
  216.   single-byte characters, and you cannot return arrays in either
  217.   language.  In C, you could have the function return a pointer to a new
  218.   string, but where would this new string come from?  Actually, when a
  219.   function returns a CHAR parameter, Force passes the address of the
  220.   return destination as an "invisible" first parameter.  This means that
  221.   the corresponding C function must receive a leading CHAR parameter.
  222.   This leading parameter is the location that the resulting string
  223.   should be stored.  Thus, the corresponding C function prototype for
  224.   the upper() function is really:
  225.  
  226.   void upper( char * destination, const char * source)
  227.  
  228.   For this example, the result of upper() will be stored in the
  229.   destination parameter.
  230.  
  231.   If you are planning to call Force functions from your C functions,
  232.   then this discussion simply applies in reverse.  That is to say, the
  233.   Force function call is made "C style" in the C program even though
  234.   this may not agree with the usual Force prototype.  Thus, if you were
  235.   to call Force's upper() function from C, you would have code similar
  236.   to the following:
  237.  
  238.     void upper( char * dest, const char * source);
  239.  
  240.     void proc( void )
  241.     {
  242.     char       string1[] = "Hello, Force!"
  243.     char       string2[50];
  244.  
  245.     upper( string2, string1 );
  246.     printf("lowercase: %s\n", string1 );
  247.     printf("UPPERcase: %s\n", string2 );
  248.  
  249.     }
  250.  
  251.   Preliminary Rules of Thumb
  252.  
  253.   Before we get into actually writing and linking C code to your Force
  254.   applications, there are a few rules that you must always heed when
  255.   working with C.
  256.  
  257.   The application may consist of as much C code as you like, but must
  258.   start at force_main(), and not C's main() function.  If most of the
  259.   application will be in C, then you may call a main()-like function as
  260.   your first or only command in force_main().  The main()-like function
  261.   may then call Force functions as described above.
  262.  
  263.   NOTE: Always compile your C code with the large memory model.
  264.  
  265.   If you are using functions in the Microsoft C library, or are using
  266.   any third party library that does, be sure to call setup_micro()
  267.   as your first command in force_main().  Also be sure to link in the
  268.   Microsoft start-up code, MICRO5.OBJ or MICRO6.OBJ depending on
  269.   which version of the compiler you have (these start-up modules are in
  270.   your \FORCE\LIB directory).
  271.  
  272.   If you are using any double precision values in your Microsoft C
  273.   code, be sure that you link in the Microsoft floating-point
  274.   startup code, MFP5.OBJ (will work for Microsoft 6.0, also).
  275.  
  276.   If you are using functions in the Borland C library, or are using any
  277.   third party library that does, be sure to call setup_turboc() as
  278.   your first command in force_main().  Also be sure to link in the
  279.   Borland start-up code, TURBOC.OBJ.
  280.  
  281.   Now let's get on with some examples.
  282.  
  283.  
  284.   Interfacing Force with Your Own C Functions
  285.  
  286.   If you are writing your own C functions to be called from Force, you
  287.   can often write them without calling any functions from the standard C
  288.   library provided with your C compiler.  This is often possible because
  289.   Force already provides similar functions for most of the functions in
  290.   the C library.  For example, standard C libraries provide several
  291.   functions for low-level file I/O.  Force provides those same
  292.   functions, as you can see in Table 8-3.
  293.  
  294.        ╒═══════════════════════════════════════════════════╕
  295.        │       Table 8-3.    File I/O functions            │
  296.        │         --------------------------------          │
  297.        │  C function                      Force function   │
  298.        │  ----------                      --------------   │
  299.        │  open()                          fb_open()        │
  300.        │  close()                         fb_close()       │
  301.        │  read()                          fb_read()        │
  302.        │  write()                         fb_write()       │
  303.        │  lseek()                         fb_seek()        │
  304.        │  eof()                           fb_eof()         │
  305.        │                                                   │
  306.        ╘═══════════════════════════════════════════════════╛
  307.  
  308.   To see this in action, here's a function written in C that uses only
  309.   Force library functions to copy a file from one filename to another.
  310.   It uses a dynamically allocated memory buffer to read and write bytes
  311.   from the first file to the second.  Note that C does not require us to
  312.   write function prototypes, but it is considered good programming
  313.   practice, as it helps the C compiler perform parameter type-checking.
  314.  
  315.     /*
  316.     * copyfile.c    -- Example code:  Calling Force library
  317.     *                  functions from a C source module.
  318.     */
  319.     typedef int LOGICAL;       /* C has no LOGICAL data type,
  320.                                ** so we roll our own. */
  321.     /*
  322.     * Here are the function prototypes for the Force library
  323.     * functions that copy_file() will be using.
  324.     */
  325.  
  326.     logical         fb_open( int *handle, const char *filename,
  327.                                int mode );
  328.     void            fb_close( int handle );
  329.     unsigned int    fb_read( int handle, void * buffer,
  330.                                unsigned int nbytes );
  331.     unsigned int    fb_write(int handle, void * buffer,
  332.                                unsigned int nbytes );
  333.     void far *      malloc( unsigned int nbytes);
  334.     void            free( void * ptr );
  335.  
  336.     /*
  337.     * File open modes.
  338.     */
  339.     #define B_READ          1
  340.     #define B_CREAD_WRITE   2
  341.     #define B_CREATE        2
  342.     #define B_WRITE         3
  343.     #define B_READ_WRITE    4
  344.     #define B_CREAD         5
  345.     #define B_CWRITE        6
  346.  
  347.     /*
  348.     * procedure: copy_file()
  349.     *
  350.     * description: copy_file() takes two filenames, and copies
  351.     *    the first  into the second.  copy_file() returns False
  352.     *    if there is an   error (such as no dynamic memory left,
  353.     *    or file does not exist).
  354.     */
  355.     logical copy_file( char * source, char * dest ) {
  356.          void far   * buffer;
  357.          int        in_handle;
  358.          int        out_handle;
  359.          int        bytes_read;
  360.     /*
  361.     *    Let's open the files, and return False if we can't.
  362.     */
  363.          if (! fb_open( &in_handle, source, B_READ ))
  364.                return( 0 );    /* return False */
  365.          if (! fb_open( &out_handle, dest, B_CWRITE ))
  366.          {
  367.                fb_close( in_handle );
  368.                return( 0 );    /* return False */
  369.          }
  370.     /*
  371.     *    Now we allocate a 5K buffer and return False if
  372.     *    we cannot get it.
  373.     */
  374.          buffer = malloc( 5120 );
  375.          if (! buffer) {
  376.                fb_close( in_handle );
  377.                fb_close( out_handle );
  378.                return( 0 );    /* return False */
  379.          }
  380.  
  381.          do {
  382.                bytes_read = fb_read( in_handle, buffer, 5120 );
  383.                fb_write( out_handle, buffer, bytes_read );
  384.          } while( bytes_read == 5120 );
  385.  
  386.          fb_close( in_handle );
  387.          fb_close( out_handle );
  388.  
  389.          return( 1 );     /* return True */
  390.     }
  391.     /*-- EOF: copyfile.c ----------------------------------*/
  392.  
  393.   Now let's write a test program in Force that uses copy_file().  Our
  394.   test program will simply have copy_file() copy the executable code
  395.   to a different name.  We'll get the name of the executable from the
  396.   Force library function get_exec().
  397.   *
  398.   * test.prg - Tests the copy_file() function
  399.   *
  400.   #include io.hdr
  401.   #include system.hdr
  402.  
  403.     FUNCTION LOGICAL copy_file PROTOTYPE
  404.          PARAMETERS CONST CHAR source,CONST CHAR dest
  405.  
  406.     PROCEDURE force_main
  407.  
  408.          VARDEF
  409.                CHAR(128)  This_File
  410.          ENDDEF
  411.  
  412.          This_File = get_exec( )
  413.          ? "Copying " + This_File + "to output.exe"
  414.          IF .NOT. copy_file( This_File, "output.exe" )
  415.                ? "Cannot copy file!"
  416.          ELSE
  417.                ? "Done!"
  418.          ENDIF
  419.  
  420.     ENDPRO
  421.     *-- EOF: test.prg --------------------------------*
  422.  
  423.   To make sure that everything works, save the C source code as
  424.   COPYFILE.C and the above Force test program as TEST.PRG.  Compile
  425.   TEST.PRG module using the following line:
  426.  
  427.   Force test.prg
  428.  
  429.   Now compile the COPYFILE.C module.  If you're using Microsoft C,
  430.   version 5.0 or 6.0, use the following line:
  431.  
  432.     cl /AL /Gs copyfile.c
  433.  
  434.   If you're using Borland's Turbo C or Borland C, compile it with this
  435.   line:
  436.  
  437.     tcc -ml -c copyfile.c
  438.  
  439.   Now you should have two more files in your directory, TEST.OBJ and
  440.   COPYFILE.OBJ and we need to link them together with the Force library.
  441.   If you're using Microsoft C, use this line:
  442.  
  443.     link test copyfile,test,Nul,force ;
  444.  
  445.   For Borland:
  446.  
  447.     TLINK test copyfile,test,nul,force ;
  448.  
  449.   Run the TEST.EXE program, and you'll see the lines:
  450.  
  451.     Copying test.exe to output.exe
  452.     done
  453.  
  454.  
  455.   Interfacing with C libraries
  456.  
  457.   Let's get a little more complicated now by using the functions in the
  458.   C library.  We'll modify our C source example to change the date of
  459.   the destination file to the date of the source file.  To do this,
  460.   we'll have to use the functions in the standard C library to read and
  461.   write file dates and times.  Unfortunately, the names of these
  462.   functions differ between Borland and Microsoft libraries, but we can
  463.   get around this problem using the C preprocessor.  Here's the new code
  464.   for COPYFILE.C.
  465.  
  466.     /*
  467.     * copyfile.c    -- Example code:  Calling Force library
  468.     *          functions from a C source module.
  469.     */
  470.     #include <io.h>
  471.     #include <dos.h>
  472.     typedef int LOGICAL;       /* C has no LOGICAL data type,
  473.                                ** so we roll our own. */
  474.     /*
  475.     * Here are the function prototypes for the Force library
  476.     * functions that copy_file() will be using.
  477.     */
  478.  
  479.     LOGICAL         fb_open( int *handle, const char *filename,
  480.                                int mode );
  481.     void            fb_close( int handle );
  482.     unsigned int    fb_read( int handle, void * buffer,
  483.                                unsigned int nbytes );
  484.     unsigned int    fb_write(int handle, void * buffer,
  485.                                unsigned int nbytes );
  486.     void far *      malloc( unsigned int nbytes);
  487.     void            free( void * ptr );
  488.  
  489.     /*
  490.     * File open modes.
  491.     */
  492.     #define B_READ        1
  493.     #define B_CREAD_WRITE 2
  494.     #define B_CREATE      2
  495.     #define B_WRITE       3
  496.     #define B_READ_WRITE  4
  497.     #define B_CREAD       5
  498.     #define B_CWRITE      6
  499.  
  500.     /*
  501.     * procedure: copy_file()
  502.     *
  503.     * description: copy_file() takes two filenames, and copies
  504.     *    the first  into the second.  copy_file() returns False
  505.     *    if there is an   error (such as no dynamic memory left,
  506.     *    or file does not exist).
  507.     */
  508.       logical copy_file( char * source, char * dest ) {
  509.          void far   * buffer;
  510.          int        in_handle;
  511.          int        out_handle;
  512.          int        bytes_read;
  513.     #ifdef _MSC_VER
  514.          unsigned   file_date, file_time;
  515.     #else
  516.          struct ftime     file_time;
  517.     #endif
  518.  
  519.     /*
  520.     *    Let's open the files, and return False if we can't.
  521.     */
  522.          if (! fb_open( &in_handle, source, B_READ ))
  523.                return( 0 );    /* return False */
  524.          if (! fb_open( &out_handle, dest, B_CWRITE )) {
  525.                fb_close( in_handle );
  526.                return( 0 );    /* return False */
  527.          }
  528.     /*
  529.     *    Here we get the time and date of the source file.
  530.     */
  531.     #    ifdef _MSC_VER
  532.                _dos_getftime( in_handle, &file_date,
  533.                                      &file_time );
  534.     #    else
  535.                getftime( in_handle, &file_time );
  536.     #    endif
  537.     /*
  538.     *    Now we allocate a 5K buffer and return False if
  539.     *    we cannot get it.
  540.     */
  541.          buffer = malloc( 5120 );
  542.          if (! buffer) {
  543.                fb_close( in_handle );
  544.                fb_close( out_handle );
  545.                return( 0 );    /* return False */
  546.          }
  547.  
  548.          do {
  549.                bytes_read = fb_read( in_handle, buffer, 5120 );
  550.                fb_write( out_handle, buffer, bytes_read );
  551.          } while( bytes_read == 5120 );
  552.  
  553.          fb_close( in_handle );
  554.     /*
  555.     *    Before we close the output file, we change its
  556.     *    date and time to that of the source file.
  557.     */
  558.     #    ifdef _MSC_VER
  559.                _dos_setftime( out_handle, file_date,
  560.                                      file_time );
  561.     #    else
  562.                setftime( out_handle, &file_time );
  563.     #    endif
  564.  
  565.          fb_close( out_handle );
  566.  
  567.          return( 1 );     /* return True */
  568.     }
  569.     /*-- EOF: copyfile.c ----------------------------------*/
  570.  
  571.   The only change that we need to make to the TEST.PRG module is to
  572.   call setup_micro() for Microsoft C or setup_turboc() for Borland's
  573.   C. If you are using the Borland C or Turbo C compiler, you'll
  574.   need to #define the macro TURBOC before #including MIXED.HDR.
  575.  
  576.     * test.prg - Tests the copy_file() function *
  577.     #include io.hdr
  578.     #include system.hdr
  579.     * #define TURBOC        // for Turbo C users
  580.     #include mixed.hdr
  581.  
  582.     FUNCTION LOGICAL copy_file PROTOTYPE
  583.          PARAMETERS CONST CHAR source, CONST CHAR dest
  584.  
  585.  
  586.     PROCEDURE force_main
  587.  
  588.          VARDEF
  589.                CHAR(128)  This_File
  590.          ENDDEF
  591.  
  592.          #ifdef TURBOC
  593.                setup_turboc()
  594.          #else
  595.                setup_micro()
  596.          #endif
  597.          This_File = get_exec( )
  598.          ? "Copying " + This_File + "to output.exe"
  599.          IF .NOT. copy_file( This_File, "output.exe" )
  600.                ? "Cannot copy file!"
  601.          ELSE
  602.                ? "Done!"
  603.          ENDIF
  604.  
  605.     ENDPRO
  606.     *-- EOF: test.prg --------------------------------
  607.  
  608.   Compile the files as you did before.  Linking them will be a little
  609.   more complex.  Recall that when you link with a C library, you have to
  610.   link in not only the object modules for the code that you have
  611.   written, but you must also link in the Force library, the large memory
  612.   model of the C library, and the start-up code for the C library.  For
  613.   this example, if you are using Microsoft C version 5.0, use this line:
  614.  
  615.     LINK test copyfile c:\force\lib\micro5, test, Nul, FORCE.LIB llibce.lib;
  616.  
  617.   If you are using Microsoft C version 6.0 change micro5 to micro6.
  618.  
  619.   For Turbo C version 2.0 through 4.0, use this line:
  620.  
  621.     TLINK /n test copyfile c:\force\lib\turboc, test, Nul, FORCE.LIB cl.lib
  622.  
  623.  
  624.                  ┌───────────────────────────────────────┐
  625.                  │ Linking C Third Party Libs into FORCE │
  626.                  └───────────────────────────────────────┘
  627.  
  628.  
  629.                 FORCE requires the C Calling Convention 
  630.                 ---------------------------------------
  631.  
  632.   The single incompatibility for FORCE and third party C libraries is
  633.   that FORCE is unable to use the PASCAL calling convention.  A major
  634.   element of the PASCAL convention involves the absence of any leading
  635.   underscore on symbol names.  Because the FORCE compiler follows the C
  636.   calling convention and automatically prepends a leading underscore, code
  637.   that it generates is incompatible with compilers that follow the PASCAL
  638.   convention.  Most prominent C third parties (such as the TurboPower libs)
  639.   customarily ship with source and it is generally simple simply to remake
  640.   the third party lib with the C convention specified, rather than PASCAL.
  641.  
  642.  
  643.                Writing "Wrappers" for Third Party C Functions
  644.                ----------------------------------------------
  645.  
  646.   The C - oriented question heard most often at Tech Support is "what must
  647.   I do to link in my familiar C third party libraries?".  Generally, the
  648.   answer is "not much", because FORCE and C approach matters very similarly
  649.   in many areas.  Most of the work involves the simple writing of a
  650.   "wrapper" function to send parameters to and get return values from the C
  651.   third party function in the proper order and form.
  652.  
  653.  
  654.   As an example of linking in standard and well behaved C third parties,
  655.   please review the following discussion of the method for writing a
  656.   simple Force "wrapper" that allows the functions contained in the
  657.   popular and versatile FUNCKy library to be called easily and simply from
  658.   Force:
  659.  
  660.   Let's use the FUNCky "dtoi" procedure to convert a date string to integer
  661.   values.  Now, Force and FUNCky use the large model, far calls, and the so
  662.   called "C calling convention".  This last means, among other things, that
  663.   the library routine names all begin with an underscore ("_").  Force
  664.   prepends the underscore to your symbols so that "dtoi()" becomes "_dtoi()
  665.   in the generated object file, thus matching the library names.  In the
  666.   FUNCky surface/core library hierarchy this means that the surface library
  667.   routine names must have the leading underscore.  The surface library
  668.   handles the language interface requirements & then calls the appropriate
  669.   core library routines.  In order to distinguish the surface and core
  670.   routine names, the core names have an additional leading underscore, ie-
  671.   in the core library our "dtoi" procedure becomes "__dtoi".  What does all
  672.   this mean to us?  The first "secret" is that we must add one underscore
  673.   to the routine name and Force adds the other. Here's how to do it:
  674.  
  675.   *- PROGRAM DTOITEST.PRG
  676.  
  677.   *- inspection of the FUNCky procedure description reveals that we need
  678.   these *  parameters in this order.  Note that we specify the length of
  679.   the date char *  string and note also the leading underscore applied to
  680.   "dtoi"
  681.  
  682.   procedure _dtoi prototype parameters const char(8) stringDate, int
  683.     iiYear, int iiYmonth, int iiDay
  684.  
  685.   *- OK, now let's test it..
  686.  
  687.   procedure force_main
  688.  
  689.     vardef
  690.       char(8)  cDate
  691.       int      iYear,iMonth,iDay
  692.     enddef
  693.  
  694.       cDate = "06/09/94"
  695.  
  696.       _dtoi(sDate, iYear, iMonth, iDay)
  697.  
  698.       ? iYear ? iMonth ? iDay
  699.  
  700.   endpro
  701.  
  702.   The second "secret" is the use of the qualifier "const" before the input
  703.   string name in the prototype.  This allows you to pass a literal string as
  704.   well as a variable name, so you could have written
  705.  
  706.   _dtoi("06/09/94",iYear,iMonth,iDay).
  707.  
  708.   Now compile & link with the core library:
  709.  
  710.       FL dtoitest,,,f:\funcky\lib\funcky2c force
  711.  
  712.  
  713.   You could always add the FUNCky lib directory to your SET LIB=...
  714.   statement and link with "FL dtoitest" but we prefer to control the link
  715.   libraries manually. This is most easily done via a makefile, of course.
  716.  
  717.  
  718.   Another challenge in converting Funcky2 to Force seems to be dealing with
  719.   the differences in parameter (data) type syntax.  We just need to pass all
  720.   values by reference and remember to use the "const" qualifier when we need
  721.   to allow the passage of a literal value. (There is also the problem that
  722.   the Clipper Julian date base is apparently different from that of Force -
  723.   Force internal dates are the number of days since day 1, year 0; we haven't
  724.   at this point researched the Clipper date base.  We therefore feel it
  725.   best to avoid   the use of julian stuff unless it is entirely "internal"
  726.   to our libraries.)
  727.  
  728.   The FUNCKy2C (core library) uses C style parameter passing and is
  729.   therefore sometimes at odds with Force _function_ parameter passing. For
  730.   example, the Funcky2 function _catstr is defined as:
  731.  
  732.      char * _catstr ( str1, str2, buffer )
  733.  
  734.   this would correspond to the Force PROCEDURE (not function)
  735.  
  736.      procedure _catstring prototype
  737.      params const char cVar1, const char cVar2, char cBuffer
  738.  
  739.   This is because, for FUNCTIONS, Force pushes a final "extra" parameter
  740.   onto the stack after the "visible" function parameters.  This extra
  741.   pointer points to the return value destination.  So, in order to turn the
  742.   Funcky2 "function" into a Force function we must use the _catstr prototype
  743.   for Force and write a wrapper:
  744.  
  745.      procedure _catstr prototype
  746.      params const char cVar1, const char cVar2, char cBuffer
  747.  
  748.      function char catstring
  749.      params const char cVar1, const char CVar2
  750.  
  751.      vardef
  752.        char buffer
  753.      enddef
  754.  
  755.        _catstring(cVar1,cVar2,buffer)
  756.  
  757.      return buffer
  758.      endfunc
  759.  
  760.   We would stick this module in our "surface" library for Force & then we
  761.   could just call catstring() whenever we want:
  762.  
  763.      ? catstring("1234","ABCdef") or newString:= catstr("Holy"," Moly!")
  764.  
  765.   This is a trivial example, of course, because we don't need a function to
  766.   concatenate strings but serves to illustrate the principle.
  767.  
  768.   Watch for things like the __itod() function - note the extra underscore.
  769.   This little tidbit (the need for the extra underscore) is burried in the
  770.   docs and is the sort of thing that can lead to much frustration and
  771.   solvent abuse.
  772.  
  773.  
  774.   The foregoing is a necessarily incomplete discussion of a fascinating
  775.   area:  the close compatibility of FORCE and C code which makes nearly all
  776.   well-behaved C libraries immediately callable from FORCE with only a
  777.   little effort!
  778.  
  779.